package mil.af.amc.adpetracker.model;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.joda.time.DateMidnight;
import org.joda.time.Duration;

import javax.persistence.*;
import java.io.Serializable;
import java.util.*;

/**
 * Represents a single Equipment Item
 *
 * @author Jason Ferguson
 */

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "T_EQUIPMENTITEM")
@org.hibernate.annotations.Entity(selectBeforeUpdate = true)
public class EquipmentItem implements Serializable, Comparable<EquipmentItem>, MappableEntity {

    private int id;
    private String ipms;
    private String serial;
    private String description;
    private double originalCost;
    private Date purchaseDate;
    private User assignedUser;
    private String location;
    private AdpeAccount account;
    private Status status;
    private List<MaintenanceEntry> maintenanceEntries = new ArrayList<MaintenanceEntry>();
    private ItemModel itemModel;
    private Condition itemCondition;
    private Status itemStatus;
    private Date lastInventoryDate;
    private DrmoPackage drmoPackage;
    private Ros rosPackage;
    private EquipmentType equipmentType;

    public EquipmentItem() {
    }

    @Id
    @Column(name = "ITEMID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ITEMID_SEQ")
    @SequenceGenerator(name = "ITEMID_SEQ", sequenceName = "S_EQUIPMENTITEM")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Column(name = "IPMS")
    public String getIpms() {
        return ipms;
    }

    public void setIpms(String ipms) {
        this.ipms = ipms;
    }

    @Column(name = "SERIAL")
    public String getSerial() {
        return serial;
    }

    public void setSerial(String serial) {
        this.serial = serial;
    }

    @Column(name = "DESCRIPTION")
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Column(name = "ORIGINALCOST")
    public double getOriginalCost() {
        return originalCost;
    }

    public void setOriginalCost(double originalCost) {
        this.originalCost = originalCost;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "PURCHASEDATE")
    public Date getPurchaseDate() {
        return purchaseDate;
    }

    public void setPurchaseDate(Date purchaseDate) {
        this.purchaseDate = purchaseDate;
    }

    @ManyToOne
    @JoinColumn(name = "ASSIGNEDUSERID")
    public User getAssignedUser() {
        return assignedUser;
    }

    public void setAssignedUser(User assignedUser) {
        this.assignedUser = assignedUser;
    }

    @Column(name = "LOCATION")
    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    @ManyToOne
    @JoinColumn(name = "ADPEACCOUNTID")
    public AdpeAccount getAccount() {
        return account;
    }

    public void setAccount(AdpeAccount account) {
        this.account = account;
    }

    @Enumerated(value = EnumType.ORDINAL)
    @Column(name = "ITEMSTATUSID")
    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    @OneToMany(mappedBy = "item")
    public List<MaintenanceEntry> getMaintenanceEntries() {
        return maintenanceEntries;
    }

    public void setMaintenanceEntries(List<MaintenanceEntry> maintenanceEntries) {
        this.maintenanceEntries = maintenanceEntries;
    }

    @ManyToOne
    @JoinColumn(name = "MODELID")
    public ItemModel getItemModel() {
        return itemModel;
    }

    public void setItemModel(ItemModel itemModel) {
        this.itemModel = itemModel;
    }

    @Enumerated(value = EnumType.ORDINAL)
    @Column(name = "CONDITION")
    public Condition getItemCondition() {
        return itemCondition;
    }

    public void setItemCondition(Condition itemCondition) {
        this.itemCondition = itemCondition;
    }

    @Enumerated(value = EnumType.ORDINAL)
    @Column(name = "STATUSID")
    public Status getItemStatus() {
        return itemStatus;
    }

    public void setItemStatus(Status itemStatus) {
        this.itemStatus = itemStatus;
    }

    @Column(name = "LASTINVENTORYDATE")
    public Date getLastInventoryDate() {
        return lastInventoryDate;
    }

    public void setLastInventoryDate(Date lastInventoryDate) {
        this.lastInventoryDate = lastInventoryDate;
    }

    @ManyToOne
    @JoinColumn(name="ROSPACKAGEID")
    public Ros getRosPackage() {
        return rosPackage;
    }

    public void setRosPackage(Ros rosPackage) {
        this.rosPackage = rosPackage;
    }

    @ManyToOne
    @JoinColumn(name = "DRMOPACKAGEID")
    public DrmoPackage getDrmoPackage() {
        return drmoPackage;
    }

    public void setDrmoPackage(DrmoPackage drmoPackage) {
        this.drmoPackage = drmoPackage;
    }

    @ManyToOne
    @JoinColumn(name = "TYPEID")
    public EquipmentType getEquipmentType() {
        return equipmentType;
    }

    public void setEquipmentType(EquipmentType equipmentType) {
        this.equipmentType = equipmentType;
    }

    @Transient
    public double getDepreciatedValue() {

        if (purchaseDate == null) {
            return 0.0;
        }

        DateMidnight baseDate = new DateMidnight(purchaseDate.getTime());
        DateMidnight today = new DateMidnight();
        Duration duration = new Duration(baseDate, today);

        // Get the number of milliseconds
        double length = duration.getMillis();
        length = length / 1000;   // get seconds
        length = length / 60; // get minutes
        length = length / 60; // get hours
        length = length / 24; // get days
        length = length / 365; // get years

        double age = 7 - length;
        if (age < 0) {
            age = 0;
        }

        double depreciatedValue = this.originalCost - (this.originalCost * 0.0073);
        depreciatedValue = depreciatedValue / 7;
        depreciatedValue *= age;

        return depreciatedValue;


    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        final EquipmentItem that = (EquipmentItem) o;

        if (serial.equals(that.serial) && itemModel.getManufacturer().equals(that.itemModel.getManufacturer())) {
            return true;
        }

        //if (!itemModel.equals(that.itemModel)) return false;
        //return serial.equals(that.serial);
        return false;

    }

    public int hashCode() {
        int result;
        result = serial.hashCode();
        result = 29 * result + itemModel.hashCode();
        return result;
    }

    public int compareTo(EquipmentItem o) {

        return this.getSerial().compareTo(o.getSerial());
    }

    public Map toMap() {

        Map resultMap = new HashMap();
        resultMap.put("id", this.getId());
        resultMap.put("name", this.getSerial());
        resultMap.put("description", this.getDescription());
        resultMap.put("manufacturer", this.getItemModel().getManufacturer());

        return resultMap;

    }
}
